home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Leisure Game Pak 1
/
Leisure Game Pak I.iso
/
lpgame1
/
04
/
source
/
gadget.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1994-08-17
|
11KB
|
380 lines
UNIT GADGET;
INTERFACE
CONST GAD_PUSHED = TRUE;
GAD_NOT_PUSHED = FALSE;
GAD_KEEP = TRUE;
GAD_NO_KEEP = FALSE;
NO_FILL = -1; { frame fill-color for no fill }
{ parameters in GADGET.refresh }
GAD_FLIP_STATE = TRUE; { flip PUSHED-state }
GAD_KEEP_STATE = FALSE; { don't flip it, keep it }
TYPE POINT_TYPE = OBJECT
x, y : WORD;
CONSTRUCTOR init(p_x, p_y : WORD);
PROCEDURE get_pos(VAR p_x, p_y : WORD);
END; { POINT_TYPE }
FRAME_TYPE = OBJECT(POINT_TYPE)
width, height : WORD;
old_col : WORD;
in_col : INTEGER; (* may be -1 = NO_FILL *)
color : ARRAY[BOOLEAN] OF WORD;
thickness : BYTE;
pushed, mouse : BOOLEAN;
CONSTRUCTOR init(f_x, f_y,
f_width, f_height : WORD;
f_thickness : BYTE;
f_in_col : INTEGER;
f_leftup_col,
f_rightdn_col : WORD;
f_pushed, f_mouse : BOOLEAN);
PROCEDURE show; VIRTUAL;
PROCEDURE hide; VIRTUAL;
END; { FRAME_TYPE }
GADGET_TYPE = OBJECT(FRAME_TYPE)
active : BOOLEAN; (* i.e. visible *)
keep : BOOLEAN; (* keeps its pushed-state *)
text : STRING[30];
text1_end : BYTE;
(* the text may consist of 2 subtexts :
characters 1..text1_end are displayed if gadget NOT_PUSHED
(text1_end+1)..LENGTH(text) ... if PUSHED
if (text1_end = 0) then "same text for both states" *)
textcol : BYTE;
CONSTRUCTOR init(g_x, g_y,
g_width,
g_height : WORD;
g_in_col : INTEGER;
g_leftup_col,
g_rightdn_col : WORD;
g_pushed,
g_mouse,
g_keep : BOOLEAN;
g_text : STRING;
g_text1_end : BYTE;
g_textcol : BYTE);
PROCEDURE show; VIRTUAL;
PROCEDURE hide; VIRTUAL;
{ refresh gadget , i.e. hide it, then show it again (eventually flip state) }
PROCEDURE refresh(flip_it : BOOLEAN);
PROCEDURE set_state(g_pushed : BOOLEAN);
FUNCTION mouse_hit(mx, my : WORD) : BOOLEAN;
FUNCTION handle_mouse_click : BOOLEAN;
FUNCTION gad_active : BOOLEAN;
FUNCTION gad_pushed : BOOLEAN;
END; { GADGET_TYPE }
{ ShadowTextXY supplies two-color text }
PROCEDURE ShadowTextXY(x, y : WORD;
up_col, dn_col : BYTE;
text : STRING);
IMPLEMENTATION
USES GRAPH,
MOUSE; (* for the gadget routines *)
{ ShadowTextXY supplies two-color text }
PROCEDURE ShadowTextXY(x, y : WORD;
up_col, dn_col : BYTE;
text : STRING);
BEGIN
SetColor(dn_col); OutTextXY(SUCC(x), SUCC(y), text);
SetColor(up_col); OutTextXY(x, y, text);
END; { ShadowTextXY }
{ ................... methods for POINT_TYPE ......................... }
CONSTRUCTOR POINT_TYPE.init(p_x, p_y : WORD);
BEGIN
SELF.x := p_x; SELF.y := p_y;
END; { POINT_TYPE.init }
PROCEDURE POINT_TYPE.get_pos(VAR p_x, p_y : WORD);
BEGIN
p_x := SELF.x; p_y := SELF.y;
END; { POINT_TYPE.get_pos }
{ ................... methods for FRAME_TYPE ......................... }
CONSTRUCTOR FRAME_TYPE.init(f_x, f_y,
f_width, f_height : WORD;
f_thickness : BYTE;
f_in_col : INTEGER;
f_leftup_col,
f_rightdn_col : WORD;
f_pushed, f_mouse : BOOLEAN);
BEGIN
POINT_TYPE.init(f_x, f_y);
SELF.width := f_width; SELF.height := f_height;
SELF.in_col := f_in_col;
SELF.color[GAD_NOT_PUSHED] := f_leftup_col;
SELF.color[GAD_PUSHED] := f_rightdn_col;
SELF.thickness := f_thickness;
SELF.pushed := f_pushed;
SELF.mouse := f_mouse;
END; { FRAME_TYPE.init }
PROCEDURE FRAME_TYPE.show;
VAR halfthick : INTEGER;
oldLINES : LineSettingsType;
oldFILLS : FillSettingsType;
oldCOLOR : WORD;
BEGIN
oldCOLOR := GetColor;
GetLineSettings(oldLINES);
GetFillSettings(oldFILLS);
SetLineStyle(SOLIDLN, 0, SELF.thickness);
IF (SELF.mouse) THEN HideMouse;
SELF.old_col := GetPixel(SELF.x, SELF.y);
IF (SELF.in_col <> NO_FILL) THEN
BEGIN
SetFillStyle (SOLIDFILL, SELF.in_col);
Bar(SELF.x, SELF.y, SELF.x + PRED(SELF.width), SELF.y + PRED(SELF.height));
END; { IF }
halfthick := SUCC(SELF.thickness) DIV 2;
{ the left and upper lines in NOT_PUSHED-color}
SetColor(SELF.color[NOT(SELF.pushed)]);
{ goto lower-left corner }
MoveTo(SELF.x - halfthick, SELF.y + PRED(SELF.height) + halfthick);
{ line to upper-left corner }
LineRel(0, -(SELF.thickness + SELF.height));
{ line to upper-right corner }
LineRel(SELF.width + SELF.thickness, 0);
{ the right and lower lines in PUSHED-color }
SetColor(SELF.color[SELF.pushed]);
{ line to lower-right corner }
LineRel(0, SELF.thickness + SELF.height);
{ line back to lower-left corner }
LineRel(-(SELF.width + SELF.thickness), 0);
IF (SELF.mouse) THEN ShowMouse;
{ back to old grafics settings }
SetColor(oldCOLOR);
WITH oldLINES DO
SetLineStyle(LineStyle, Pattern, Thickness);
WITH oldFILLS DO
SetFillStyle(Pattern, Color);
END; { FRAME_TYPE.show }
PROCEDURE FRAME_TYPE.hide;
VAR oldFILLS : FillSettingsType;
oldLINES : LineSettingsType;
oldCOLOR : WORD;
BEGIN
IF (SELF.mouse) THEN HideMouse;
IF (SELF.in_col = NO_FILL) THEN
BEGIN
oldCOLOR := GetColor;
SetColor(SELF.old_col);
GetLineSettings(oldLINES);
SetLineStyle(SOLIDLN, 0, SELF.thickness);
Rectangle(SELF.x, SELF.y,
SELF.x + PRED(SELF.width),
SELF.y + PRED(SELF.height));
SetColor(oldCOLOR);
WITH oldLINES DO
SetLineStyle(LineStyle, Pattern, Thickness);
END { IF }
ELSE
BEGIN
GetFillSettings(oldFILLS);
SetFillStyle (SOLIDFILL, SELF.old_col);
Bar(SELF.x - SELF.thickness, SELF.y - SELF.thickness,
SELF.x + PRED(SELF.width) + SELF.thickness,
SELF.y + PRED(SELF.height) + SELF.thickness);
WITH oldFILLS DO
SetFillStyle(Pattern, Color);
END; { ELSE }
IF (SELF.mouse) THEN ShowMouse;
END; { FRAME_TYPE.hide }
{ ................... methods for GADGET_TYPE ........................ }
CONSTRUCTOR GADGET_TYPE.init(g_x, g_y,
g_width,
g_height : WORD;
g_in_col : INTEGER;
g_leftup_col,
g_rightdn_col : WORD;
g_pushed,
g_mouse,
g_keep : BOOLEAN;
g_text : STRING;
g_text1_end : BYTE;
g_textcol : BYTE);
BEGIN
FRAME_TYPE.init(g_x, g_y, g_width, g_height,
NORMWIDTH,
g_in_col, g_leftup_col, g_rightdn_col,
g_pushed, g_mouse);
SELF.text := g_text;
SELF.text1_end := g_text1_end;
SELF.textcol := g_textcol;
SELF.keep := g_keep;
SELF.active := FALSE;
END; { GADGET_TYPE.init }
PROCEDURE GADGET_TYPE.show;
VAR txtcol : WORD;
act_text : STRING;
BEGIN
FRAME_TYPE.show;
IF (SELF.mouse) THEN HideMouse;
IF (SELF.pushed) THEN
BEGIN
txtcol := 0; {should be BLACK}
(* get the text's second part for PUSHED gadgets,
if text1_end = 0 then it's the whole text, ok! *)
act_text := COPY(text, text1_end+1, LENGTH(text));
END
ELSE
BEGIN
txtcol := SELF.textcol;
IF (text1_end > 0) THEN
(* show the first part *)
act_text := COPY(text, 1, text1_end)
ELSE
(* there's only one text for both states *)
act_text := text;
END;
ShadowTextXY(SELF.x + SUCC(SELF.width - TextWidth(act_text)) DIV 2,
SELF.y + SUCC(SELF.height - TextHeight(act_text)) DIV 2,
txtcol, SELF.textcol - txtcol,
act_text);
IF (SELF.mouse) THEN ShowMouse;
SELF.active := TRUE;
END; { GADGET_TYPE.show }
PROCEDURE GADGET_TYPE.hide;
BEGIN
IF (SELF.active) THEN
FRAME_TYPE.hide; {don't hide it if it's not there}
SELF.active := FALSE;
END; { GADGET_TYPE.hide }
{ refresh gadget , i.e. hide it, then show it again (eventually flip state) }
PROCEDURE GADGET_TYPE.refresh(flip_it : BOOLEAN);
BEGIN
SELF.pushed := SELF.pushed XOR flip_it;
SELF.hide;
SELF.show;
END; { GADGET_TYPE.refresh }
{ set new pushed-state }
PROCEDURE GADGET_TYPE.set_state(g_pushed : BOOLEAN);
BEGIN
SELF.pushed := g_pushed;
END; { GADGET_TYPE.set_state }
{ tests whether coordinates (mx, my) are in gadget }
FUNCTION GADGET_TYPE.mouse_hit(mx, my : WORD) : BOOLEAN;
{ in_rect(x,y,x1,y1,dx,dy) <=> (x,y) is in (x1,y1)-(x1+dx-1, y1+dy-1) }
FUNCTION in_rect(x, y, x1, y1, dx, dy : INTEGER) : BOOLEAN;
BEGIN
in_rect := (x >= x1) AND (x < x1+dx) AND (y >= y1) AND (y < y1+dy);
END; { in_rect }
BEGIN
mouse_hit := SELF.active AND
in_rect(mx, my, SELF.x, SELF.y, SELF.width, SELF.height);
END; { GADGET_TYPE.mouse_hit }
{ handles mouseclick (inclusive reading mouse, drawing graphics) }
FUNCTION GADGET_TYPE.handle_mouse_click : BOOLEAN;
VAR dummy, mx, my : WORD;
was_pushed, (* push state on call *)
new_hit, old_hit : BOOLEAN; (* hit status: new, until now *)
BEGIN
old_hit := FALSE;
dummy := GetMousePos(mx, my);
IF (SELF.mouse_hit(mx, my)) THEN
BEGIN
was_pushed := SELF.pushed;
WHILE (GetMousePos(mx, my) = LEFTMOUSEBUTTON) DO
BEGIN
new_hit := SELF.mouse_hit(mx, my);
IF (old_hit XOR new_hit) THEN
BEGIN
(* refresh it, only if necessary *)
IF (SELF.pushed XOR (new_hit OR was_pushed)) THEN
BEGIN
SELF.pushed := new_hit OR was_pushed;
SELF.refresh(FALSE);
END; (* IF *)
old_hit := new_hit;
END; (* IF *)
END; (* WHILE *)
END; (* IF *)
{ if it was pressed before button was released then refresh it }
IF (old_hit) THEN
BEGIN
IF (SELF.pushed XOR (SELF.keep AND NOT(was_pushed))) THEN
BEGIN
SELF.pushed := NOT(SELF.pushed);
SELF.refresh(FALSE);
END; (* IF *)
END; (* IF old_hit *)
handle_mouse_click := old_hit;
END; { GADGET_TYPE.handle_mouse_click }
{ returns TRUE if gadget is active (i.e. visible) }
FUNCTION GADGET_TYPE.gad_active : BOOLEAN;
BEGIN
gad_active := SELF.active;
END; { gad_active }
{ returns TRUE if gadget is pressed }
FUNCTION GADGET_TYPE.gad_pushed : BOOLEAN;
BEGIN
gad_pushed := SELF.pushed;
END; { gad_pushed }
END. { UNIT GADGET }